Repository navigation
Generate TypeScript and Python route snippets from openapi.yaml - #461
Conversation
|
@Naajih09 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
tsc --noEmit clean vitest 99 files, 1140 passing (up from 97 / 1135) dropped-tests none #280 close the vulnerabilities that are actually reachable #426 keep watched pairs as metric labels, bounded #529 GET /price/:asset/fiat for local currency #530 standard 429 response contract with retryAfter #530 pairs well with what landed earlier: #307 standardised empty-vs-missing status codes, and this does the same for rate limiting. An API that answers 429 without telling a client when to come back forces every consumer to invent its own backoff, and they will not agree. #461 (generate TypeScript and Python route snippets from the OpenAPI spec) was dropped. It fails three of its own tests even after running `npm run snippets:gen`: × render deterministically × committed files match the generator × contain no placeholder hosts or addresses The regeneration produced no files at all, so the generator is not doing what the test expects of it. The third case is the one I care about most -- a snippet carrying a placeholder address is exactly how an invented contract id reaches a contributor, which has already cost us a sweep. Worth getting right rather than merging around. Claude-Session: https://claude.ai/code/session_01USgemLt4Rnz4SGB1Srf3GB
Miracle656
left a comment
There was a problem hiding this comment.
Held — three of this PR's own tests fail, and they still fail after running the generator:
× render deterministically
× committed files match the generator
× contain no placeholder hosts or addresses
I ran npm run snippets:gen on the merged tree and it produced no files at all — git status was clean afterwards. So either the generator is not writing where the test looks, or it is exiting before it writes. Worth checking that first; the other two failures may well fall out of it.
The third case is the one I would fix even if the others were passing. A snippet that ships a placeholder host or address is precisely how an invented contract id reaches a contributor — a previous issue batch of ours shortened one contract id and five people invented their own to fill the gap, which cost a full review sweep to untangle. A generated snippet is worse again, because it looks authoritative and people paste it.
So: every address in a generated snippet should be either a real, full, 56-character value from the spec, or so obviously fake that nobody could mistake it for one. Nothing in between.
The idea is good and I want it — a client snippet that cannot drift from the spec is worth having, and it pairs with #403's generated TypeScript client. Get the generator writing and the three tests green and I will take it.
|
@Miracle656
|
|
Status update — this is close, and the blocker is mechanical. Against current That guard is the best thing in the PR, so I want to be clear I am not asking you to weaken it. Refusing to generate when a route belongs to no group is what stops the snippets quietly covering 60% of the API while looking complete — the exact failure mode the hand-written curl examples had. Keep it exactly as it is. What it needs is the route list catching up. Most are a one-line addition to an existing group. A few are judgement calls worth making deliberately rather than sweeping into
The rest ( Once the list is complete, regenerate the committed snippets so Then a full One suggestion for the medium term, not now: this is the fifth generated artifact in the repo that a stale route list can break ( |
|
Merged into A snippet generator that invents a plausible-looking asset code produces copy-pasteable commands that fail for the reader, which is worse than no snippet. Throwing instead pushes the fix into the spec, where it benefits the docs and the client too. Byte-comparing the committed snippets against a fresh render is the right guard for the same reason. Three things had to be reconciled with Grouping had to move to the bare route. Since 97c50bf every documented path carries Eight GET routes had no group. This is the list I flagged last round, now resolved rather than enumerated: Two required parameters had no example, which is exactly the failure mode the generator is designed for. Covering those routes surfaced That last point connects to something worth knowing: tsc clean, |
|
Closing as merged — your work is on It does not show as auto-merged because you pushed 245ac4c (a merge of Nothing of yours was dropped: |
|
@Naajih09 — my apologies for the timing. You were mid-fix and I closed this out from under you. That was avoidable and I should have checked before closing rather than after. To be clear about where things stand: your work is merged, and this PR is now correctly marked as merged rather than closed. I have reopened it and recorded the merge so the record matches what actually happened. Here is exactly what landed and where:
You can verify the first one yourself: What happened on my side, since you deserve the actual reason rather than an apology alone: I fetched your branch, reviewed it, fixed three things that broke when One thing worth knowing: your branch at 245ac4c is now a subset of If you want the natural follow-up, there is a real one and it is yours if you want it. The generated README endpoint table has zero rows carrying a query string: so Thanks for the work, and sorry again for the way this went. |


Body:
Closes #277
What this does
Adds a generator that writes TypeScript and Python snippets for each GET route group in
openapi.yaml, so the snippets are derived from the spec and cannot drift from it.scripts/gen-snippets.ts: readsopenapi.yaml, groups GET routes by path prefix (price,analytics,service), and renders one.tsand one.pyfile per group undersnippets/.tests/snippets.test.ts: checks that the generator is deterministic, that the committed snippet files match a fresh render, and that no snippet contains a placeholder host or address.package.json: addssnippets:gen.The generator fails the build if a GET route is neither in a group nor listed in
SKIPPED, so a new route cannot be dropped silently.Running the snippets
Each snippet reads its configuration from the environment and fails with a clear message if something is missing:
LENS_BASE_URL(required): the live service URL.STELLAR_SECRET(TypeScript, gated routes): a testnet secret key used to sign x402 payments.LENS_X_PAYMENT(Python, gated routes): a pre-signed base64X-PAYMENTheader.LENS_API_KEY(/usage/me): a client API key.No key, secret, or address is written into any snippet.
Known limits
openapi.yamllistslocalhost:4000, the README listslocalhost:3002, and neither is a live service. I need the maintainers to confirm it before this can be verified end to end.@x402/fetch. I haven't confirmed a Python signer, so the Python gated snippets expect a pre-signedLENS_X_PAYMENTheader. This is a stopgap.npm run snippets:genandnpm testmay surface errors./graphqlis skipped becausedocs/graphql.mdcovers it./graphqlis not payment-gated, and the spec marks its POST as gated. The generator follows the spec. Please confirm which is correct.networktotestnet. Snippets send that default explicitly.